home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 6 / QRZ Ham Radio Callsign Database - Volume 6.iso / mac / files / amiga / rhinosrc.lha / kernel.c < prev    next >
C/C++ Source or Header  |  1993-06-17  |  14KB  |  600 lines

  1. /* Non pre-empting synchronization kernel, machine-independent portion
  2.  * Copyright 1992 Phil Karn, KA9Q
  3.  */
  4. #undef PROCLOG
  5. #if    defined(PROCLOG)
  6. #include <stdio.h>
  7. #endif
  8. #ifdef MSDOS
  9. #include <dos.h>
  10. #endif
  11. #include <setjmp.h>
  12. #include "global.h"
  13. #include "mbuf.h"
  14. #include "proc.h"
  15. #include "timer.h"
  16. #include "socket.h"
  17. #include "daemon.h"
  18. #include "hardware.h"
  19.  
  20. #ifdef    PROCLOG
  21. FILE *proclog;
  22. #endif
  23. int Stkchk = 1;
  24. struct proc *Curproc;        /* Currently running process */
  25. struct proc *Rdytab;        /* Processes ready to run (not including curproc) */
  26. struct proc *Waittab[PHASH];    /* Waiting process list */
  27. struct proc *Susptab;        /* Suspended processes */
  28. static struct mbuf *Killq;
  29. struct ksig Ksig;
  30.  
  31. static void addproc __ARGS((struct proc *entry));
  32. static void delproc __ARGS((struct proc *entry));
  33.  
  34. static void _psignal __ARGS((void *event,int n));
  35. static int procsigs __ARGS((void));
  36.  
  37. /* Create a process descriptor for the main function. Must be actually
  38.  * called from the main function, and must be called before any other
  39.  * tasking functions are called!
  40.  *
  41.  * Note that standard I/O is NOT set up here.
  42.  */
  43. struct proc *
  44. mainproc(name)
  45. char *name;
  46. {
  47.     register struct proc *pp;
  48.  
  49.     /* Create process descriptor */
  50.     pp = (struct proc *)callocw(1,sizeof(struct proc));
  51.  
  52.     /* Create name */
  53.     pp->name = strdup(name);
  54. #ifndef AMIGA
  55.     pp->stksize = 0;
  56. #else
  57.     init_psetup(pp);
  58. #endif
  59.     /* Make current */
  60.     pp->state = READY;
  61.     Curproc = pp;
  62.  
  63. #ifdef    PROCLOG
  64.     proclog = fopen("proclog",APPEND_TEXT);
  65. #endif
  66.     return pp;
  67. }
  68. /* Create a new, ready process and return pointer to descriptor.
  69.  * The general registers are not initialized, but optional args are pushed
  70.  * on the stack so they can be seen by a C function.
  71.  */
  72. struct proc *
  73. newproc(name,stksize,pc,iarg,parg1,parg2,freeargs)
  74. char *name;        /* Arbitrary user-assigned name string */
  75. unsigned int stksize;    /* Stack size in words to allocate */
  76. void (*pc)();           /* Initial execution address */
  77. int iarg;        /* Integer argument (argc) */
  78. void *parg1;        /* Generic pointer argument #1 (argv) */
  79. void *parg2;        /* Generic pointer argument #2 (session ptr) */
  80. int freeargs;        /* If set, free arg list on parg1 at termination */
  81. {
  82.     register struct proc *pp;
  83.     int i;
  84.  
  85.     if(Stkchk)
  86.         chkstk();
  87.  
  88.     /* Create process descriptor */
  89.     pp = (struct proc *)callocw(1,sizeof(struct proc));
  90.  
  91.     /* Create name */
  92.     pp->name = strdup(name);
  93.  
  94.     /* Allocate stack */
  95. #ifdef    AMIGA
  96.     stksize = max(stksize,512);
  97.     stksize *= 2;        /* int16's -> int32's */
  98.     stksize += SIGQSIZE0;    /* DOS overhead */
  99. #endif
  100.     pp->stksize = stksize;
  101.     if((pp->stack = (int16 *)malloc(sizeof(int16)*stksize)) == NULL){
  102.         free(pp->name);
  103.         free((char *)pp);
  104.         return NULLPROC;
  105.     }
  106.     /* Initialize stack for high-water check */
  107.     for(i=0;i<stksize;i++)
  108.         pp->stack[i] = STACKPAT;
  109.  
  110.     /* Do machine-dependent initialization of stack */
  111.     psetup(pp,iarg,parg1,parg2,pc);
  112.  
  113.     if(freeargs)
  114.         pp->flags |= P_FREEARGS;
  115.     pp->iarg = iarg;
  116.     pp->parg1 = parg1;
  117.     pp->parg2 = parg2;
  118.  
  119.     /* Inherit creator's input and output sockets */
  120.     pp->input = fdup(stdin);
  121.     pp->output = fdup(stdout);
  122.  
  123.     /* Add to ready process table */
  124.     pp->state = READY;
  125.     addproc(pp);
  126. #ifdef    PROCLOG
  127.     fprintf(proclog,"newproc id %lx name %s stack %u/%u\n",ptol(pp),
  128.         pp->name,stkutil(pp),pp->stksize);
  129.     fflush(proclog);
  130. #endif
  131.     return pp;
  132. }
  133.  
  134. /* Free resources allocated to specified process. If a process wants to kill
  135.  * itself, the reaper is called to do the dirty work. This avoids some
  136.  * messy situations that would otherwise occur, like freeing your own stack.
  137.  */
  138. void
  139. killproc(pp)
  140. register struct proc *pp;
  141. {
  142.     char **argv;
  143.  
  144.     if(pp == NULLPROC)
  145.         return;
  146.     /* Don't check the stack here! Will cause infinite recursion if
  147.      * called from a stack error
  148.      */
  149.     if(pp == Curproc)
  150.         killself();     /* Doesn't return */
  151.     fclose(pp->input);
  152.     fclose(pp->output);
  153.  
  154.     /* Stop alarm clock in case it's running */
  155.     stop_timer(&pp->alarm);
  156.  
  157.     /* Alert everyone waiting for this proc to die */
  158.     psignal(pp,0);
  159.  
  160.     /* Remove from appropriate table */
  161.     delproc(pp);
  162.  
  163. #ifdef    PROCLOG
  164.     fprintf(proclog,"killproc id %lx name %s stack %u/%u\n",ptol(pp),
  165.         pp->name,stkutil(pp),pp->stksize);
  166.     fclose(proclog);
  167.     proclog = fopen("proclog",APPEND_TEXT);
  168. #endif
  169.     /* Free allocated memory resources */
  170.     if(pp->flags & P_FREEARGS){
  171.         argv = pp->parg1;
  172.         while(pp->iarg-- != 0)
  173.             free(*argv++);
  174.         free(pp->parg1);
  175.     }
  176.     free(pp->name);
  177.     free(pp->stack);
  178.     free((char *)pp);
  179. }
  180. /* Terminate current process by sending a request to the killer process.
  181.  * Automatically called when a process function returns. Does not return.
  182.  */
  183. void
  184. killself()
  185. {
  186.     register struct mbuf *bp;
  187.  
  188.     bp = pushdown(NULLBUF,sizeof(Curproc));
  189.     memcpy(bp->data,(char *)&Curproc,sizeof(Curproc));
  190.     enqueue(&Killq,bp);
  191.  
  192.     /* "Wait for me; I will be merciful and quick." */
  193.     for(;;)
  194.         pwait(NULL);
  195. }
  196. /* Process used by processes that want to kill themselves */
  197. void
  198. killer(i,v1,v2)
  199. int i;
  200. void *v1;
  201. void *v2;
  202. {
  203.     struct proc *pp;
  204.     struct mbuf *bp;
  205.  
  206.     for(;;){
  207.         while(Killq == NULLBUF)
  208.             pwait(&Killq);
  209.         bp = dequeue(&Killq);
  210.         pullup(&bp,(char *)&pp,sizeof(pp));
  211.         free_p(bp);
  212.         if(pp != Curproc)       /* We're immortal */
  213.             killproc(pp);
  214.     }
  215. }
  216.  
  217. /* Inhibit a process from running */
  218. void
  219. suspend(pp)
  220. struct proc *pp;
  221. {
  222.     if(pp == NULLPROC)
  223.         return;
  224.     if(pp != Curproc)
  225.         delproc(pp);    /* Running process isn't on any list */
  226.     pp->state |= SUSPEND;
  227.     if(pp != Curproc)
  228.         addproc(pp);    /* pwait will do it for us */
  229.     else
  230.         pwait(NULL);
  231. }
  232. /* Restart suspended process */
  233. void
  234. resume(pp)
  235. struct proc *pp;
  236. {
  237.     if(pp == NULLPROC)
  238.         return;
  239.     delproc(pp);    /* Can't be Curproc! */
  240.     pp->state &= ~SUSPEND;
  241.     addproc(pp);
  242. }
  243.  
  244. /* Wakeup waiting process, regardless of event it's waiting for. The process
  245.  * will see a return value of "val" from its pwait() call. Must not be
  246.  * called from an interrupt handler.
  247.  */
  248. void
  249. alert(pp,val)
  250. struct proc *pp;
  251. int val;
  252. {
  253.     if(pp == NULLPROC)
  254.         return;
  255. #ifdef    notdef
  256.     if((pp->state & WAITING) == 0)
  257.         return;
  258. #endif
  259. #ifdef    PROCTRACE
  260.     log(-1,"alert(%lx,%u) [%s]",ptol(pp),val,pp->name);
  261. #endif
  262.     if(pp != Curproc)
  263.         delproc(pp);
  264.     pp->state &= ~WAITING;
  265.     pp->retval = val;
  266.     pp->event = NULL;
  267.     if(pp != Curproc)
  268.         addproc(pp);
  269. }
  270.  
  271. /* Post a wait on a specified event and give up the CPU until it happens. The
  272.  * null event is special: it means "I don't want to block on an event, but let
  273.  * somebody else run for a while". It can also mean that the present process
  274.  * is terminating; in this case the wait never returns.
  275.  *
  276.  * Pwait() returns 0 if the event was signaled; otherwise it returns the
  277.  * arg in an alert() call. Pwait must not be called from interrupt level.
  278.  *
  279.  * Before waiting and after giving up the CPU, pwait() processes the signal
  280.  * queue containing events signaled when interrupts were off. This means
  281.  * the process queues are no longer modified by interrupt handlers,
  282.  * so it is no longer necessary to run with interrupts disabled here. This
  283.  * greatly improves interrupt latencies.
  284.  */
  285. int
  286. pwait(event)
  287. void *event;
  288. {
  289.     register struct proc *oldproc;
  290.     int tmp;
  291.     int i_state;
  292.  
  293. #ifdef notdef
  294.     if(!istate()){
  295.         stktrace();
  296.     }
  297. #endif
  298.     Ksig.pwaits++;
  299.     if(intcontext()){
  300.         /* Pwait must not be called from interrupt context */
  301.         Ksig.pwaitints++;
  302.         return 0;
  303.     }
  304.  
  305.     if(event != NULL){
  306.         /* Post a wait for the specified event */
  307.         Curproc->event = event;
  308.         Curproc->state = WAITING;
  309.         addproc(Curproc);       /* Put us on the wait list */
  310.     }
  311.     /* Enable interrupts, after saving the current state.
  312.      * This minimizes interrupt latency since we may have a lot
  313.      * of work to do. This seems safe, since care has been taken
  314.      * here to ensure that signals from interrupt level are not lost, e.g.,
  315.      * if we're waiting on an event, we post it before we scan the
  316.      * signal queue.
  317.      *//* moved to -after- posting wait by Rhialto */
  318.     i_state = istate();
  319.     enable();
  320.     if(Stkchk)
  321.         chkstk();
  322.     /* If the signal queue contains a signal for the event that we're
  323.      * waiting for, this will wake us back up
  324.      */
  325.     procsigs();
  326.     if(event == NULL){
  327.         /* We remain runnable */
  328.         if(Rdytab == NULLPROC){
  329.             /* Nothing else is ready, so just return */
  330.             Ksig.pwaitnops++;
  331.             restore(i_state);
  332.             return 0;
  333.         }
  334.         addproc(Curproc); /* Put us on the end of the ready list */
  335.     }
  336.     /* Look for a ready process and run it. If there are none,
  337.      * loop or halt until an interrupt makes something ready.
  338.      */
  339.     while(Rdytab == NULLPROC){
  340.         /* Give system back to upper-level multitasker, if any.
  341.          * Note that this function enables interrupts internally
  342.          * to prevent deadlock, but it restores our state
  343.          * before returning.
  344.          */
  345.         kbint();        /***/
  346.         giveup();
  347.         /* Process signals that occurred during the giveup() */
  348.         procsigs();
  349.     }
  350.     /* Remove first entry from ready list */
  351.     oldproc = Curproc;
  352.     Curproc = Rdytab;
  353.     delproc(Curproc);
  354.  
  355.     /* Now do the context switch.
  356.      * This technique was inspired by Rob, PE1CHL, and is a bit tricky.
  357.      *
  358.      * First save the current process's state. Then if
  359.      * this is still the old process, load the new environment. Since the
  360.      * new task will "think" it's returning from the setjmp() with a return
  361.      * value of 1, the comparison with 0 will bypass the longjmp(), which
  362.      * would otherwise cause an infinite loop.
  363.      */
  364. #ifdef    PROCTRACE
  365.     if(strcmp(oldproc->name,Curproc->name) != 0){
  366.         log(-1,"-> %s(%d)",Curproc->name,!!(Curproc->flags & P_ISTATE));
  367.     }
  368. #endif
  369.     /* Save old state */
  370.     oldproc->flags &= ~P_ISTATE;
  371.     if(i_state)
  372.         oldproc->flags |= P_ISTATE;
  373.     if(setjmp(oldproc->env) == 0){
  374.         /* We're still running in the old task; load new task context.
  375.          * The interrupt state is restored here in case longjmp
  376.          * doesn't do it (e.g., systems other than Turbo-C).
  377.          */
  378.         restore(Curproc->flags & P_ISTATE);
  379.         longjmp(Curproc->env,1);
  380.     }
  381.     /* At this point, we're running in the newly dispatched task */
  382.     tmp = Curproc->retval;
  383.     Curproc->retval = 0;
  384.  
  385.     /* Also restore the true interrupt state here, in case the longjmp
  386.      * DOES restore the interrupt state saved at the time of the setjmp().
  387.      * This is the case with Turbo-C's setjmp/longjmp.
  388.      */
  389.     restore(Curproc->flags & P_ISTATE);
  390.  
  391.     /* If an exception signal was sent and we're prepared, take it */
  392.     if((Curproc->flags & P_SSET) && tmp == Curproc->signo)
  393.         longjmp(Curproc->sig,1);
  394.  
  395.     /* Otherwise return normally to the new task */
  396.     return tmp;
  397. }
  398.  
  399. void
  400. psignal(event,n)
  401. void *event;
  402. int n;
  403. {
  404.     static void *lastevent;
  405.  
  406.     if(istate()){
  407.         /* Interrupts are on, just call _psignal directly after
  408.          * processing the previously queued signals
  409.          */
  410.         procsigs();
  411.         _psignal(event,n);
  412.         return;
  413.     }
  414.     /* Interrupts are off, so quickly queue event */
  415.     Ksig.psigsqueued++;
  416.  
  417.     /* Ignore duplicate signals to protect against a mad device driver
  418.      * overflowing the signal queue
  419.      */
  420.     if(event == lastevent && Ksig.nentries != 0){
  421.         Ksig.dupsigs++;
  422.         return;
  423.     }
  424.     if(Ksig.nentries == SIGQSIZE){
  425.         /* It's hard to handle this gracefully */
  426.         Ksig.lostsigs++;
  427.         return;
  428.     }
  429.     lastevent = Ksig.wp->event = event;
  430.     Ksig.wp->n = n;
  431.     if(++Ksig.wp >= &Ksig.entry[SIGQSIZE])
  432.         Ksig.wp = Ksig.entry;
  433.     Ksig.nentries++;
  434. }
  435. static int
  436. procsigs()
  437. {
  438.     int cnt = 0;
  439.     int tmp;
  440.  
  441.     for(;;){
  442.         /* Atomic read and decrement of entry count */
  443.         DISABLE();
  444.         tmp = Ksig.nentries;
  445.         if(tmp != 0)
  446.             Ksig.nentries--;
  447.         RESTORE();
  448.         if(tmp == 0)
  449.             break;
  450.         _psignal(Ksig.rp->event,Ksig.rp->n);
  451.         if(++Ksig.rp >= &Ksig.entry[SIGQSIZE])
  452.             Ksig.rp = Ksig.entry;
  453.         cnt++;
  454.     }
  455.     if(cnt > Ksig.maxentries)
  456.         Ksig.maxentries = cnt;    /* Record high water mark */
  457.     return cnt;
  458. }
  459. /* Make ready the first 'n' processes waiting for a given event. The ready
  460.  * processes will see a return value of 0 from pwait().  Note that they don't
  461.  * actually get control until we explicitly give up the CPU ourselves through
  462.  * a pwait(). _psignal is now called from pwait, which is never called at
  463.  * interrupt time, so it is no longer necessary to protect the proc queues
  464.  * against interrupts. This also helps interrupt latencies considerably.
  465.  */
  466. static void
  467. _psignal(event,n)
  468. void *event;    /* Event to signal */
  469. int n;        /* Max number of processes to wake up */
  470. {
  471.     register struct proc *pp;
  472.     struct proc *pnext;
  473.     unsigned int hashval;
  474.     int cnt = 0;
  475.  
  476.     Ksig.psigs++;
  477.     if(Stkchk)
  478.         chkstk();
  479.  
  480.     if(event == NULL){
  481.         Ksig.psignops++;
  482.         return;     /* Null events are invalid */
  483.     }
  484.     /* n == 0 means "signal everybody waiting for this event" */
  485.     if(n == 0)
  486.         n = 65535;
  487.  
  488.     hashval = phash(event);
  489.     for(pp = Waittab[hashval];n != 0 && pp != NULLPROC;pp = pnext){
  490.         pnext = pp->next;
  491.         if(pp->event == event){
  492. #ifdef    PROCTRACE
  493.                 log(-1,"psignal(%lx,%u) wake %lx [%s]",ptol(event),n,
  494.                  ptol(pp),pp->name);
  495. #endif
  496.             delproc(pp);
  497.             pp->state &= ~WAITING;
  498.             pp->retval = 0;
  499.             pp->event = NULL;
  500.             addproc(pp);
  501.             n--;
  502.             cnt++;
  503.         }
  504.     }
  505.     for(pp = Susptab;n != 0 && pp != NULLPROC;pp = pnext){
  506.         pnext = pp->next;
  507.         if(pp->event == event){
  508. #ifdef    PROCTRACE
  509.                 log(-1,"psignal(%lx,%u) wake %lx [%s]",ptol(event),n,
  510.                  ptol(pp),pp->name);
  511. #endif /* PROCTRACE */
  512.             delproc(pp);
  513.             pp->state &= ~WAITING;
  514.             pp->event = 0;
  515.             pp->retval = 0;
  516.             addproc(pp);
  517.             n--;
  518.             cnt++;
  519.         }
  520.     }
  521.     if(cnt == 0)
  522.         Ksig.psignops++;
  523.     else
  524.         Ksig.psigwakes += cnt;
  525. }
  526.  
  527. /* Rename a process */
  528. void
  529. chname(pp,newname)
  530. struct proc *pp;
  531. char *newname;
  532. {
  533.     free(pp->name);
  534.     pp->name = strdup(newname);
  535. }
  536. /* Remove a process entry from the appropriate table */
  537. static void
  538. delproc(entry)
  539. register struct proc *entry;    /* Pointer to entry */
  540. {
  541.     if(entry == NULLPROC)
  542.         return;
  543.  
  544.     if(entry->next != NULLPROC){
  545.         entry->next->prev = entry->prev;
  546.     }
  547.     if(entry->prev != NULLPROC){
  548.         entry->prev->next = entry->next;
  549.     } else {
  550.         switch(entry->state){
  551.         case READY:
  552.             Rdytab = entry->next;
  553.             break;
  554.         case WAITING:
  555.             Waittab[phash(entry->event)] = entry->next;
  556.             break;
  557.         case SUSPEND:
  558.         case SUSPEND|WAITING:
  559.             Susptab = entry->next;
  560.             break;
  561.         }
  562.     }
  563. }
  564. /* Append proc entry to end of appropriate list */
  565. static void
  566. addproc(entry)
  567. register struct proc *entry;    /* Pointer to entry */
  568. {
  569.     register struct proc *pp;
  570.     struct proc **head;
  571.  
  572.     if(entry == NULLPROC)
  573.         return;
  574.  
  575.     switch(entry->state){
  576.     case READY:
  577.         head = &Rdytab;
  578.         break;
  579.     case WAITING:
  580.         head = &Waittab[phash(entry->event)];
  581.         break;
  582.     case SUSPEND:
  583.     case SUSPEND|WAITING:
  584.         head = &Susptab;
  585.         break;
  586.     }
  587.     entry->next = NULLPROC;
  588.     if(*head == NULLPROC){
  589.         /* Empty list, stick at beginning */
  590.         entry->prev = NULLPROC;
  591.         *head = entry;
  592.     } else {
  593.         /* Find last entry on list */
  594.         for(pp = *head;pp->next != NULLPROC;pp = pp->next)
  595.             ;
  596.         pp->next = entry;
  597.         entry->prev = pp;
  598.     }
  599. }
  600.